package com.megvii.corelib.util;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.YuvImage;
import android.util.Log;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * Created by linyue on 15/12/27.
 */
public class ImageUtil
{
    public static byte[] bitmapToBytes(Bitmap bitmap)
    {
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        bitmap.compress(Bitmap.CompressFormat.JPEG, 75, bos);
        byte[] bytes = bos.toByteArray();
        return bytes;
    }

    public static String saveBitmap(Context mContext, Bitmap bitmaptosave)
    {
        if (bitmaptosave == null)
        {
            return null;
        }

        File mediaStorageDir = mContext.getExternalFilesDir("koala_individual");

        if (!mediaStorageDir.exists())
        {
            if (!mediaStorageDir.mkdirs())
            {
                return null;
            }
        }
        // String bitmapFileName = System.currentTimeMillis() + ".jpg";
        String bitmapFileName = System.currentTimeMillis() + "";
        FileOutputStream fos = null;
        try
        {
            fos = new FileOutputStream(mediaStorageDir + "/" + bitmapFileName);
            boolean successful = bitmaptosave.compress(Bitmap.CompressFormat.JPEG, 75, fos);

            if (successful)
            {
                return mediaStorageDir.getAbsolutePath() + "/" + bitmapFileName;
            }
            else
            {
                return null;
            }
        }
        catch (FileNotFoundException e)
        {
            e.printStackTrace();
            return null;
        }
        finally
        {
            try
            {
                fos.close();
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
        }
    }

    /**
     * untested function
     *
     * 如果图片太大，会内存溢出
     */
    public static byte[] getNV21(Bitmap scaled, int inputWidth, int inputHeight) throws OutOfMemoryError
    {
        int[] argb = new int[inputWidth * inputHeight];

        scaled.getPixels(argb, 0, inputWidth, 0, 0, inputWidth, inputHeight);

        byte[] yuv = new byte[inputWidth * inputHeight * 3 / 2];
        encodeYUV420SP(yuv, argb, inputWidth, inputHeight);

        scaled.recycle();

        return yuv;
    }

    public static void encodeYUV420SP(byte[] yuv420sp, int[] argb, int width, int height)
    {
        final int frameSize = width * height;

        int yIndex = 0;
        int uvIndex = frameSize;

        int a, R, G, B, Y, U, V;
        int index = 0;
        for (int j = 0; j < height; j++)
        {
            for (int i = 0; i < width; i++)
            {

                a = (argb[index] & 0xff000000) >> 24; // a is not used obviously
                R = (argb[index] & 0xff0000) >> 16;
                G = (argb[index] & 0xff00) >> 8;
                B = (argb[index] & 0xff) >> 0;

                // well known RGB to YUV algorithm
                Y = ((66 * R + 129 * G + 25 * B + 128) >> 8) + 16;
                U = ((-38 * R - 74 * G + 112 * B + 128) >> 8) + 128;
                V = ((112 * R - 94 * G - 18 * B + 128) >> 8) + 128;

                // NV21 has a plane of Y and interleaved planes of VU each sampled by a factor of 2
                //    meaning for every 4 Y pixels there are 1 V and 1 U.  Note the sampling is every other
                //    pixel AND every other scanline.
                yuv420sp[yIndex++] = (byte) ((Y < 0) ? 0 : ((Y > 255) ? 255 : Y));
                if (j % 2 == 0 && index % 2 == 0)
                {
                    yuv420sp[uvIndex++] = (byte) ((V < 0) ? 0 : ((V > 255) ? 255 : V));
                    yuv420sp[uvIndex++] = (byte) ((U < 0) ? 0 : ((U > 255) ? 255 : U));
                }

                index++;
            }
        }
    }

    public static Bitmap createBitmapFromNV21(byte[] nv21Data, int imageFormat, int width,
            int height, int rotation, boolean mirror, int maxSize)
    {
        YuvImage yuvImage = new YuvImage(nv21Data, imageFormat, width, height, null);
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        yuvImage.compressToJpeg(new Rect(0, 0, width, height), 80, byteArrayOutputStream);
        byte[] jpegData = byteArrayOutputStream.toByteArray();
        Bitmap bitmap = BitmapFactory.decodeByteArray(jpegData, 0, jpegData.length);
        Matrix matrix = new Matrix();
        matrix.reset();
        matrix.setRotate(rotation);
        if (mirror)
        {
            matrix.postScale(-1, 1);
        }
        bitmap = Bitmap
                .createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
        bitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true);
        int max = bitmap.getHeight() > bitmap.getWidth() ? bitmap.getHeight() : bitmap.getWidth();
        float scale = max / maxSize;
        if (scale > 1)
        {
            bitmap = Bitmap.createScaledBitmap(bitmap, (int) (bitmap.getWidth() / scale),
                    (int) (bitmap.getHeight() / scale), false);
        }
        return bitmap;
    }

    public static Bitmap cutImageByHead(Bitmap bitmap, RectF rect, boolean normalizedRect, boolean mirror)
    {
        if (normalizedRect)
        {
            rect = new RectF(rect);
            rect.left *= bitmap.getWidth();
            rect.top *= bitmap.getHeight();
            rect.right *= bitmap.getWidth();
            rect.bottom *= bitmap.getHeight();
        }

        if (mirror)
        {
            rect = new RectF(rect);
            float left = bitmap.getWidth() - rect.right;
            float right = bitmap.getWidth() - rect.left;
            rect.left = left;
            rect.right = right;
        }

        float width = rect.width() * 2;
        if (width > bitmap.getWidth())
        {
            width = bitmap.getWidth();
        }

        float height = rect.height() * 2;
        if (height > bitmap.getHeight())
        {
            height = bitmap.getHeight();
        }

        float l = rect.centerX() - (width / 2);
        if (l < 0)
        {
            l = 0;
        }
        float t = rect.centerY() - (height / 2);
        if (t < 0)
        {
            t = 0;
        }
        if (l + width > bitmap.getWidth())
        {
            width = bitmap.getWidth() - l;
        }
        if (t + height > bitmap.getHeight())
        {
            height = bitmap.getHeight() - t;
        }

        return Bitmap.createBitmap(bitmap, (int) l, (int) t, (int) width, (int) height);
    }

    public static Bitmap createBitmapWithFaceFrame(Bitmap bitmap, Bitmap faceFrame,
            RectF normalizedRect, boolean mirror)
    {
        if (mirror)
        {
            normalizedRect = new RectF(normalizedRect);
            float left = 1 - normalizedRect.right;
            float right = 1 - normalizedRect.left;
            normalizedRect.left = left;
            normalizedRect.right = right;
        }
        float width = bitmap.getWidth();
        float height = bitmap.getHeight();
        float frameWidth = faceFrame.getWidth();
        float frameHeight = faceFrame.getHeight();
        float scaleX = width / frameWidth * normalizedRect.width();
        float scaleY = height / frameHeight * normalizedRect.height();
        float translateX = normalizedRect.left * width;
        float translateY = normalizedRect.top * height;
        Matrix matrix = new Matrix();
        matrix.setScale(scaleX, scaleY);
        matrix.postTranslate(translateX, translateY);
        Bitmap result = Bitmap.createBitmap(bitmap);
        Canvas canvas = new Canvas(result);
        Paint paint = new Paint();
        canvas.drawBitmap(faceFrame, matrix, paint);
        return result;
    }

    /**
     * 按比例缩小bitmap，使图片长宽都不得超过maxWidthOrHeight，如果原本都没有超过maxWidthOrHeight，就返回原来的bitmap
     * @param maxWidthOrHeight
     * @return
     */
    public static Bitmap createScaledBitmap(Bitmap bitmap, int maxWidthOrHeight)
    {
        float width = bitmap.getWidth();
        float height = bitmap.getHeight();
        float scale = 1;
        if (width > height)
        {
            scale = maxWidthOrHeight / width;
        }
        else
        {
            scale = maxWidthOrHeight / height;
        }
        if (scale > 1)
        {
            return bitmap;
        }
        int scaledWidth = (int) (width * scale);
        int scaleHeight = (int) (height * scale);
        Bitmap scaled = Bitmap.createScaledBitmap(bitmap, scaledWidth, scaleHeight, false);
        return scaled;
    }


    /**
     * size推荐800
     */
    @SuppressLint("NewApi")
    public static Bitmap centralDecoder(String oriFilepath, int size)
    {
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        options.inPreferQualityOverSpeed = true;
        BitmapFactory.decodeFile(oriFilepath, options);
        if (options.outWidth == -1 || options.outHeight == -1)// 图像有问题
        {
            return null;
        }
        int scale = (options.outHeight > options.outWidth ? options.outHeight : options.outWidth) / size;
        if (scale < 1)
        {
            scale = 1;
        }
        options.inJustDecodeBounds = false;
        options.inSampleSize = scale;
        return BitmapFactory.decodeFile(oriFilepath, options);
    }
}
